<?php
/**
 * @desc controller class file
 * @author nana
 * @date 2011
 *
 */
class NICED_Controller extends NICED_Container
{
    protected     $requestName;
	protected     $exception;
    protected static $mInstantiateTypes = array('controller', 'action', 'model', 'view', 'template');

	public function __construct($request_name = null)
	{
        $this->requestName = $request_name;
	}
	
	public function execute() 
	{
	}

	public function dispatch($request_name = null) 
	{
		//action
		$action = $this->instantiate($request_name, 'action', $this);

		if ($action instanceof NICED_Action) 
		{
			$result = $action->execute();
		} 
		else 
		{
			throw new NICED_NotExistsException('instantiate action fail');
		}

		//view
		$view_name = $this->retrieveViewName($request_name, $result);

		if (!$view_name) 
		{
			throw new NICED_NotExistsException('retrieve view name '.$view_name.' fail!');
		}
		
		$view = $this->instantiate($view_name, 'view', $this);

		if ($view instanceof NICED_View) 
		{
			$view->execute();
		} 
		else
		{
			throw new NICED_NotExistsException('instantiate view '.$view_name.' fail!');
		}
	}

    public function selectAction()
    {
        return $this->requestName;
    }
	
	public function selectView($result)
	{
		return $this->requestName;
	}

	public function getRequest()
	{
		return NICED_Request::getInstance();
	}

    public function getRequestName()
    {
        return $this->requestName;
    }

	public function getMessageDieViewName()
	{
		return 'Default.MessageDie';
	}
	
	public function getModel($model_name) 
	{
		$model_name = strtolower($model_name);
        $model = NICED_Application::$container->get('models.'.$model_name);

		if ($model) 
		{
			return $model;
		}

		$model = $this->instantiate($model_name, 'model', $this);

		if ($model instanceof NICED_Model) 
		{
            NICED_Application::$container->set('models.'.$model_name, $model);

			return $model;
		}
		else
		{
			throw new NICED_NotExistsException('get model '.$model_name.' fail, not exists');
		}
	}	
	 
    public static function instantiate($request_name, $type, $param = null, $instance = true) 
	{
		NICED_Request::checkRequestName($request_name);

        $slice = NICED_Request::parseRequestName($request_name);
        $class_name = str_replace(' ', '_', ucwords(implode(' ', $slice))).'_'.ucwords($type);
		$name       = strtolower($request_name);
		$file_path  = null;

        if(!class_exists($class_name, false))
        {
			$paths = self::getInstantiateFilePath($name, $type);

			foreach ($paths as $path)
			{
				if (file_exists($path)) 
				{
					$file_path = $path;
					break;
				}			
			}
						
			if ($file_path)
			{
				include_once($path);
			}
			else
			{
				throw new NICED_NotExistsException($class_name.' class file not exists, search path is :'.var_export($paths, true));
			}
        }

		if (!$instance)
		{
			return true;
		}

        if (!class_exists($class_name, false) && 'controller' == $type)
        {
            $count = count($slice); 
            array_pop($slice);
            $name  = implode('_', $slice);
		    $class_name = ucwords($name).'_Controller';
        }

        if(class_exists($class_name, false)) 
        {
            if ('controller' == $type)
            {
                return new $class_name($request_name, $param);
            }
            else
            {
                return new $class_name($param);
            }
        }
        else
        {
            throw new NICED_NotExistsException($class_name.' '.$type.' class does not exists');
        }
    }

	public static function getInstantiateFilePath($request_name, $type)
	{
        $types = &self::$mInstantiateTypes;
		if (!in_array($type, $types))
		{
			throw new NICED_ValidationException('type is invalid!');
		}

		NICED_Request::checkRequestName($request_name);

		$paths        = array();
		$request_name = strtolower($request_name);

        $slice = NICED_Request::parseRequestName($request_name);
        $count = count($slice); 
        $name  = $slice[$count - 1];
        array_pop($slice);
        $base  = implode('/',$slice);

		$paths[] = DIR_APPS.$base.'/'.$type.'s/'.$name.'.'.$type.'.php';	
		$paths[] = DIR_APPS.$base.'/'.$name.'.'.$type.'.php';

        if ('controller' == strtolower($type))
        {
            $name = $slice[$count - 2]; 
			$paths[] = DIR_APPS.$base.'/'.$type.'s/'.$name.'.controller.php';
			$paths[] = DIR_APPS.$base.'/'.$name.'.controller.php';
        }

		return $paths;
	}

	public function buildSelectViewName() 
	{
        $request_name = $this->requestName;
		$method = 'selectView_'.str_replace('.', '_', $request_name);

		if (!method_exists($this, $method)) 
		{
			$method = 'selectView';
		} 

		return $method;
	}

	//for handle exception in action, and get exception in view
	public function handleException($e)
	{
		$this->exception = $e;
	}

	public function getException()
	{
		return $this->exception;
	}
} //end class
